/*
 * @Author: your name
 * @Date: 2021-08-14 22:25:16
 * @LastEditTime: 2021-08-14 23:31:45
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /io复用/select2.cpp
 */

#include <sys/socket.h>//socket基础api
#include <sys/types.h>
#include <string.h>//bzero
#include <fcntl.h>//fcntl

#include <sys/select.h>//select
#include <netinet/in.h>//socket地址类型
#include <unistd.h>

#include <iostream>
using namespace std;

#define exit_if(r, ...) if(r) {printf(__VA_ARGS__); printf("error no: %d error msg %s\n", errno, strerror(errno)); exit(1);}

char buf[1024];//应用层接受缓冲区
int len=0;

void SetReuse(int fd)
{
    int reuse=1;
    setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&reuse,(socklen_t)sizeof reuse);
}
void setNonBlock(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    exit_if(flags<0, "fcntl failed");
    int r = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    exit_if(r<0, "fcntl failed");
}
int Init_Socket()
{
    short port=9999;
    struct sockaddr_in seraddr;
    bzero(&seraddr,sizeof seraddr);
    seraddr.sin_addr.s_addr=INADDR_ANY;
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(port);
    int lfd=socket(AF_INET,SOCK_STREAM,0);
    exit_if(lfd==-1,"socket() error");
    setNonBlock(lfd);
    SetReuse(lfd);
    exit_if(::bind(lfd,(const sockaddr*)&seraddr,(socklen_t)sizeof seraddr)==-1,"bind() error");
    exit_if(listen(lfd,100)==-1,"listen() error");
    return lfd;
}
int HandleConnection(int fd,bool flag)
{
    struct sockaddr_in cliaddr;
    socklen_t addrlen=sizeof cliaddr;
    bzero(&cliaddr,sizeof cliaddr);
    if(flag)
    {
        int connfd=accept(fd,(struct sockaddr*)&cliaddr,&addrlen);
        exit_if(connfd==-1,"accept() error");
        return connfd;
    }
    close(fd);
    return 0;

}
int HandleRead(int fd)
{
    int len=recv(fd,buf,sizeof buf,0);
    if(len==0)
        return 0;
    exit_if(len==-1,"read()错误");
    cout<<"read "<<len<<" bytes: "<<buf<<endl;//*****telnet的问题，/r/n
    send(fd,buf,len,0);
    return len;
}

int main()
{
    int lfd=Init_Socket();

    fd_set rfds;//默认只有1024个，最多支持1024个fd
    FD_ZERO(&rfds);
    fd_set wfds;
    FD_ZERO(&wfds);
    fd_set bak;
    FD_SET(lfd,&rfds);
    bak=rfds;//**********

    int ret,nready=0,maxfd=lfd;
    struct timeval time,timetemp;
    time.tv_sec=5;
    time.tv_usec=0;
    timetemp=time;
    for(;;)
    {
        //每次循环之前的动作
        memset(buf,'\0',sizeof buf);
        rfds=bak;
        timetemp=time;
        
        nready=select(maxfd+1,&rfds,NULL,NULL,&timetemp);
        //cout<<"nready= "<<nready<<",maxfd= "<<maxfd<<endl;
        if(nready==0)
        {
            cout<<timetemp.tv_sec<<"s内暂无事件发生"<<endl;
            continue;
        }
        else if(nready==-1)
            exit_if(1,"select() error");
        for(int j=0;j<=maxfd;j++)//不是<，而是<=
        {
            if(nready==0)
                break;
            if(j==lfd&&FD_ISSET(j,&rfds))//******
            {
                ret=HandleConnection(lfd,true);
                FD_SET(ret,&bak);//******
                maxfd=max(ret,maxfd);//******
                nready--;
            }
            else if(FD_ISSET(j,&rfds))
            {
                len=HandleRead(j);
                if(len==0)//*********
                {
                    HandleConnection(j,false);
                    FD_CLR(j,&bak);
                    continue;
                }
                nready--;
            }
        }
    }
    close(lfd);
    return 0;
}